import cli.CommandLineOptions;
import cli.CommandLineParser;
import cli.ConfigManager;
import flowdroid.Pipeline;
import org.xmlpull.v1.XmlPullParserException;
import util.Constant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.HashMap;


public class Main {
    /**
     * 获取命令行参数,读取配置,并且调用执行
     *
     * @param args 命令行参数 java Main apk_path
     * @throws IOException 文件不存在等IO问题
     */
    public static void main(String[] args) throws IOException, XmlPullParserException, URISyntaxException {
        CommandLineOptions options = parseCommandLineArgs(args);

        Main main = new Main();
        ConfigManager configManager = ConfigManager.getInstance();;
        // 重定向: 如果在 local 运行,直接重定向输出; Server 上可以用 nohup
        if (configManager.recordSystemOutLog) {
            String systemOutPath = new File(options.getTestPath()).getParent() + File.separator + Constant.dateFormatter.format(LocalDateTime.now()) + "-SystemOut.log";
            //if systemOutPath already exists
            if (new File(systemOutPath).exists()) {
                int cnt = 0;
                while (new File(systemOutPath).exists()) {
                    systemOutPath = new File(options.getTestPath()).getParent() + File.separator + Constant.dateFormatter.format(LocalDateTime.now()) + "-SystemOut"
                            + cnt + ".log";
                    cnt++;
                }
            }
            System.out.println("Start redirecting System.out output to file:" + systemOutPath);
            redirectSystemOut(systemOutPath);
        }

        main.processApks(options,configManager);
    }

    private void processApks(CommandLineOptions options, ConfigManager configManager) {
        HashMap<String, String> map = options.map;

        for (String apkPath : map.keySet()) {
            analyzeApk(apkPath,configManager);
        }
    }

    private void analyzeApk(String apkPath, ConfigManager configManager) {
        try {
            File f = new File(apkPath);
            String name = Constant.getApkNameFromApkFilepath(f.getName());
//            String androidJarPlatform = "/home/fyl/project/code/AndroPrivacyConsistency/libs/platforms";
//            String analysisResDumpDir = "/home/fyl/project/code/AndroPrivacyConsistency/data/dump" + "/" + name;
//            String sysOutRedirect = analysisResDumpDir + File.separator + "system.out";
//            redirectSystemOut(sysOutRedirect);
//            System.out.println("redirect system.out to file:" + sysOutRedirect);
//            System.err.println("redirect system.out to file:" + sysOutRedirect);
//            Constant.createDirectoryIfNotExists(analysisResDumpDir);

            String analysisResDumpDir = new File(apkPath).getParent() + File.separator + name;
            Constant.createDirectoryIfNotExists(analysisResDumpDir);

            // 2. 构造调用图
            System.gc();
            Pipeline.pipeline(apkPath, configManager, analysisResDumpDir);
            System.gc();
        } catch (Exception e) {
            System.out.println("Error when analyzing apk:" + apkPath);
            System.out.println("Error occurred in Main.analyzeApk()");
            System.out.flush();
        }
    }


    private static CommandLineOptions parseCommandLineArgs(String[] args) {
        CommandLineOptions options;
        do {
            options = CommandLineParser.parseArgs(args);
        } while (options == null);
        return options;
    }


    /**
     * only for local machine 重定向,便于保存运行日志.
     *
     * @param path 重定向文件路径
     */
    private static void redirectSystemOut(String path) {
        try {
            PrintStream out = new PrintStream(new FileOutputStream(path, true));
            System.setOut(out);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
